<?php

class App 
{
	/**
	 *
	 * @var \App 
	 */
	private static $_instance;
	
	/**
	 *
	 * @var \DbSimple_Connect
	 */
	protected static $_db;
	
	/**
	 * 
	 * @return \App
	 */
	public static function getInstance()
	{
		if(!self::$_instance)
			self::$_instance = new self;
		
		return self::$_instance;
	}
	
	
	/**
	 * Autoloaded files
	 * @var array
	 */
	protected $_autoloaded = array();

	/**
	 * Application configuration
	 * @var array
	 */
	private $_configs = array();

	/**
	 *
	 * @var object
	 */
	private $_layout;
	
	/**
	 *
	 * @var \Core\Base\Table
	 */
	private $_model = array();


	/**
	 * Run application
	 */
	public static function run($configs)
	{
		$inst = App::getInstance();
		
		App::configs($configs);
		
		\spl_autoload_register('App::autoload');
		
		$bootstrap = new App\Bootstrap();
		$bootstrap->run();
		
		$inst->_callController();
	}
	
	protected function _callController()
	{
		$path = APPLICATION_PATH .'/modules/'. \App::routers()->getModuleName() .'/controller/' . ucfirst(\App::routers()->getControllerName()) . '.php';
		
		if($h = fopen($path, 'r'))
		{
			fclose($h);

			require_once $path;
			
			$controller = "\\Modules\\". \App::routers()->getModuleName() .'\\'. \App::routers()->getControllerName();
			$action = \App::routers()->getActionName() . 'Action';
			
			$obj = new $controller();
			
			$obj->$action();
			
			$obj->renderLayout();
		}
	}

	public static function load($path)
	{
		if(!$path)
			return false;
		
		$path = str_replace('\\', '/', $path);
		$path = explode('/', $path);
		
		$class = end($path);
		$class = substr($class, 0, strpos($class, '.')-1);
		
		$obj = new $class;
		
		return $obj;
	}
	
	/**
	 * 
	 * @param string $class with namespace
	 * @return string loaded file
	 */
	public static function autoload($file)
	{
		if(!$file)
			return false;
		
		$instanse = self::getInstance();
		
		$file = str_replace('\\', '/', $file);
		
		$classPos = strrpos($file, '/');
		
		$class = substr($file, $classPos + 1);
		
		$classPath = strtolower(substr($file, 0, $classPos) );
		
		$autoload = $instanse->configs()->autoload;
		array_unshift($autoload, '');
		
		foreach($autoload as $lib)
		{
			$loadPath = APPLICATION_PATH . ($lib ? '/'. $lib : '') .'/'. $classPath .'/'. $class .'.php';
			
			if($h = @fopen($loadPath, 'r'))
			{
				fclose($h);
				
				require_once $loadPath;
				
				$instanse->addLoadedFile($file, $loadPath);
				
				return $file;
			}
		}

		return false;
	}
	
	public function getModel($model)
	{
		if(isset($this->_model[$model]))
			return $this->_model[$model];

		return $this->_model[$model] = new $model;
	}
	
	
	public function __set($key, $val)
	{
		$this->$key = $val;
	}
	
	public function __get($key)
	{
		return $this->$key;
	}
	
	/**
	 * Cache loaded file
	 * @param string $file
	 * @return \Core\App
	 */
	public function addLoadedFile($file, $path = '')
	{
		$this->_autoloaded[$file] = $path;
		return $this;
	}
	
	public static function configs($configs = null)
	{
		$inst = App::getInstance();
		
		if($configs)
		{
			$inst->_configs = $configs;
		}
		
		return (object)$inst->_configs;
	}
	
	/**
	 *
	 * @return \Core\Routers 
	 */
	public static function routers()
	{
		return \Core\Routers::getInstance();
	}
	
	public function setLayout($layout)
	{
		$this->_layout = $layout;
	}
	
	public function getLayout()
	{
		return $this->_layout;
	}
	
	public static function layout($layout = null)
	{
		if($layout)
		{
			\App::getInstance()->setLayout($layout);
		}
		
		return \App::getInstance()->getLayout();
	}
	
	/**
	 *
	 * @param \DbSimple_Connect $db
	 * @return \DbSimple_Connect 
	 */
	public static function db($db = null)
	{
		if($db)
		{
			self::$_db = $db;
		}
		
		return self::$_db;
	}
	
	public static function model($model)
	{
		if(!$model)
			return null;
		
		$model = '\\Models\\'. $model;
		
		return \App::getInstance()->getModel($model);
	}
	
}